package org.light.domain;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.light.core.Writeable;
import org.light.exception.ValidateException;
import org.light.utils.DomainUtil;
import org.light.utils.FieldUtil;
import org.light.utils.StringUtil;
import org.light.utils.WriteableUtil;
import org.light.verb.FindById;

public class DummyDaoImpl extends DaoImpl {
	private static final long serialVersionUID = -7376733796370937661L;

	@Override
	public String generateDaoImplString() throws ValidateException{
		if (this.domain instanceof org.light.domain.Enum) {
			return generateEnumDummyDaoImplStatements().getContent();
		}else {
			return generateDummyDaoImplStatements().getContent();
		}
	}	

	public StatementList generateDummyDaoImplStatements() throws ValidateException{
		List<Writeable> sList = new ArrayList<Writeable>();
		
		Set<String> imports = this.generateImportStrings();
		imports.add("database/sql");
		imports.add("strings");
		if (this.domain.containsDateTime()) {
			imports.add(DomainUtil.packagetokenToGoPackageFolder(this.domain.getProjectName(),this.domain.getPackageToken()+".utils"));
		}
		imports.add(DomainUtil.packagetokenToGoPackageFolder(this.domain.getProjectName(),this.domain.getPackageToken()+"."+this.domain.getDomainSuffix()));
		imports.addAll(this.classImports);
		
		sList.add(new Statement(500L,0,"package " + this.domain.getDaoimplSuffix()));
		StatementList sl = DomainUtil.generateImportStatements(imports);
		sl.setSerial(1000L);
		sl.setIndent(0);
		sList.add(sl);
		long serial = 1000L;
		
		for (ManyToMany mtm : this.domain.getManyToManies()) {
			sList.add(new Statement(serial+1000L,0,"type Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+" struct {"));
			sList.add(new Statement(serial+2000L,1,""+mtm.getMaster().getCapFirstDomainName()+"Id     int64 `json:\""+mtm.getMaster().getLowerFirstDomainName()+"Id\"`"));
			sList.add(new Statement(serial+3000L,1,StringUtil.capFirst(mtm.getSlaveAlias())+"Id int64 `json:\""+StringUtil.lowerFirst(mtm.getSlaveAlias())+"Id\"`"));
			sList.add(new Statement(serial+4000L,0,"}"));
			sList.add(new Statement(serial+5000L,0,""));
			sList.add(new Statement(serial+6000L,0,"func (Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+" *Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+") Get"+mtm.getMaster().getCapFirstDomainName()+"Id() int64 {"));
			sList.add(new Statement(serial+7000L,1,"return Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+"."+mtm.getMaster().getCapFirstDomainName()+"Id"));
			sList.add(new Statement(serial+8000L,0,"}"));
			sList.add(new Statement(serial+9000L,0,""));
			sList.add(new Statement(serial+10000L,0,"func (Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+" *Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+") Set"+mtm.getMaster().getCapFirstDomainName()+"Id("+mtm.getMaster().getCapFirstDomainName()+"Id int64) {"));
			sList.add(new Statement(serial+11000L,1,"Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+"."+mtm.getMaster().getCapFirstDomainName()+"Id = "+mtm.getMaster().getCapFirstDomainName()+"Id"));
			sList.add(new Statement(serial+12000L,0,"}"));
			sList.add(new Statement(serial+13000L,0,""));
			sList.add(new Statement(serial+14000L,0,"func (Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+" *Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+") Get"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id() int64 {"));
			sList.add(new Statement(serial+15000L,1,"return Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+"."+StringUtil.capFirst(mtm.getSlaveAlias())+"Id"));
			sList.add(new Statement(serial+16000L,0,"}"));
			sList.add(new Statement(serial+17000L,0,""));
			sList.add(new Statement(serial+18000L,0,"func (Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+" *Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+") Set"+StringUtil.capFirst(mtm.getSlaveAlias())+"Id("+StringUtil.capFirst(mtm.getSlaveAlias())+"Id int64) {"));
			sList.add(new Statement(serial+19000L,1,"Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+mtm.getMaster().getDomainNamingSuffix()+"."+StringUtil.capFirst(mtm.getSlaveAlias())+"Id = "+StringUtil.capFirst(mtm.getSlaveAlias())+"Id"));
			sList.add(new Statement(serial+20000L,0,"}"));
			serial += 21000L;
		}

		
		sList.add(new Statement(serial+2000L,0,""));
		sList.add(new Statement(serial+3000L,0,"var "+this.domain.getLowerFirstDomainName()+"Db []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+" = init"+this.domain.getCapFirstDomainName()+"Db()"));
		
		serial += 4000L;
		for (ManyToMany mtm : this.domain.getManyToManies()) {
			sList.add(new Statement(serial,0,"var "+mtm.getMaster().getLowerFirstDomainName() +StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb = init"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb()"));
			serial += 1000L;
		}
		
		sList.add(new Statement(serial+4000L,0,""));
		sList.add(new Statement(serial+5000L,0,"func init"+this.domain.getCapFirstDomainName()+"Db() []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+" {"));
		sList.add(new Statement(serial+6000L,1,"_db := []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+"{"));
		serial += 7000L;
		for (Domain d: this.domain.getDummyDb()) {			
			sList.add(new Statement(serial,2,"{"));
			serial += 1000L;
			for (Field f: d.getFields()) {
				sList.add(new Statement(serial,2,f.getCapFirstFieldName()+": "+FieldUtil.findTypeValueToken(f)+","));
				serial += 1000L;
			}
			sList.add(new Statement(serial,2,"},"));
			serial += 1000L;
		}		
		sList.add(new Statement(serial+3000L,1,"}"));
		sList.add(new Statement(serial+4000L,1,"return _db"));
		sList.add(new Statement(serial+5000L,0,"}"));
		
		sList.add(new Statement(serial+6000L,0,""));
		sList.add(new Statement(serial+7000L,0,"func Get"+this.domain.getCapFirstDomainName()+"Db() []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+" {"));
		sList.add(new Statement(serial+8000L,1,"return "+this.domain.getLowerFirstDomainName()+"Db"));
		sList.add(new Statement(serial+9000L,0,"}"));
		sList.add(new Statement(serial+10000L,0,""));
		sList.add(new Statement(serial+11000L,0,"func max"+this.domain.getCapFirstDomainName()+"Id() int64 {"));
		sList.add(new Statement(serial+12000L,1,"var max int64 = 0"));
		sList.add(new Statement(serial+13000L,1,"for _, "+this.domain.getLowerFirstDomainName()+" := range Get"+this.domain.getCapFirstDomainName()+"Db() {"));
		sList.add(new Statement(serial+14000L,2,"if "+this.domain.getLowerFirstDomainName()+".Get"+this.domain.getDomainId().getCapFirstFieldName()+"() > max {"));
		sList.add(new Statement(serial+15000L,3,"max = "+this.domain.getLowerFirstDomainName()+".Get"+this.domain.getDomainId().getCapFirstFieldName()+"()"));
		sList.add(new Statement(serial+16000L,2,"}"));
		sList.add(new Statement(serial+17000L,1,"}"));
		sList.add(new Statement(serial+18000L,1,"return max"));
		sList.add(new Statement(serial+19000L,0,"}"));
		
		serial += 20000L;
		
		for (ManyToMany mtm:this.domain.getManyToManies()) {
			sList.add(new Statement(serial,0,"func init"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+"LinkDb() [] Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+" {"));
			sList.add(new Statement(serial+1000L,1,"_db := [] Link"+mtm.getMaster().getCapFirstDomainName()+StringUtil.capFirst(mtm.getSlaveAlias())+this.domain.getDomainNamingSuffix()+"{"));
			
			serial += 2000L;
			
			List<ManyToMany> dataMtms = DomainUtil.filterMtms(this.domain.getDummyDb(),mtm);
			for (ManyToMany dmtm: dataMtms) {
				for (String slaveValue:dmtm.getSlaveValuesList()) {
					sList.add(new Statement(serial,1,"{"));
					sList.add(new Statement(serial+1000L,2,dmtm.getMaster().getCapFirstDomainName()+"Id: "+dmtm.getMasterValue()+","));
					sList.add(new Statement(serial+2000L,2,StringUtil.capFirst(dmtm.getSlaveAlias())+"Id: "+slaveValue+","));
					sList.add(new Statement(serial+3000L,1,"},"));
					serial += 4000L;
				}
			}		
			sList.add(new Statement(serial,1,"}"));
			sList.add(new Statement(serial+1000L,1,"return _db"));
			sList.add(new Statement(serial+2000L,0,"}"));

			serial += 3000L;
		}
		
		for (Method m : this.getMethods()) {
			StatementList msl = m.generateMethodFullStatements();
			msl.setSerial(serial);
			msl.setIndent(1);
			sList.add(msl);
			serial += 1000L;
		}

		return WriteableUtil.merge(sList);
	}
	
	public StatementList generateEnumDummyDaoImplStatements() throws ValidateException{
		List<Writeable> sList = new ArrayList<Writeable>();
		
		Set<String> imports = this.generateImportStrings();
		imports.add("database/sql");
		imports.add("strings");
		if (this.domain.containsDateTime()) {
			imports.add(DomainUtil.packagetokenToGoPackageFolder(this.domain.getProjectName(),this.domain.getPackageToken()+".utils"));
		}
		imports.add(DomainUtil.packagetokenToGoPackageFolder(this.domain.getProjectName(),this.domain.getPackageToken()+"."+this.domain.getDomainSuffix()));
		imports.addAll(this.classImports);
		
		sList.add(new Statement(500L,2,"package " + this.domain.getDaoimplSuffix()));
		StatementList sl = DomainUtil.generateImportStatements(imports);
		sl.setSerial(1000L);
		sl.setIndent(0);
		sList.add(sl);
		long serial = 1000L;
		sList.add(new Statement(serial+2000L,0,""));
		sList.add(new Statement(serial+3000L,0,"var "+this.domain.getLowerFirstDomainName()+"Db []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+" = init"+this.domain.getCapFirstDomainName()+"Db()"));
		sList.add(new Statement(serial+4000L,0,""));
		sList.add(new Statement(serial+5000L,0,"func init"+this.domain.getCapFirstDomainName()+"Db() []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+" {"));
		sList.add(new Statement(serial+6000L,1,"_db := []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+"{"));
		serial += 7000L;
		for (Domain d: this.domain.getDummyDb()) {			
			sList.add(new Statement(serial,2,"{"));
			serial += 1000L;
			for (Field f: d.getFields()) {
				sList.add(new Statement(serial,2,f.getCapFirstFieldName()+": "+FieldUtil.findTypeValueToken(f)+","));
				serial += 1000L;
			}
			sList.add(new Statement(serial,2,"},"));
			serial += 1000L;
		}		
		sList.add(new Statement(serial+3000L,1,"}"));
		sList.add(new Statement(serial+4000L,1,"return _db"));
		sList.add(new Statement(serial+5000L,0,"}"));
		
		sList.add(new Statement(serial+6000L,0,""));
		sList.add(new Statement(serial+7000L,0,"func Get"+this.domain.getCapFirstDomainName()+"Db() []"+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix()+" {"));
		sList.add(new Statement(serial+8000L,1,"return "+this.domain.getLowerFirstDomainName()+"Db"));
		sList.add(new Statement(serial+9000L,0,"}"));
		sList.add(new Statement(serial+10000L,0,""));
		sList.add(new Statement(serial+11000L,0,"func max"+this.domain.getCapFirstDomainName()+"Id() int64 {"));
		sList.add(new Statement(serial+12000L,1,"var max int64 = 0"));
		sList.add(new Statement(serial+13000L,1,"for _, "+this.domain.getLowerFirstDomainName()+" := range Get"+this.domain.getCapFirstDomainName()+"Db() {"));
		sList.add(new Statement(serial+14000L,2,"if "+this.domain.getLowerFirstDomainName()+".Get"+this.domain.getDomainId().getCapFirstFieldName()+"() > max {"));
		sList.add(new Statement(serial+15000L,3,"max = "+this.domain.getLowerFirstDomainName()+".Get"+this.domain.getDomainId().getCapFirstFieldName()+"()"));
		sList.add(new Statement(serial+16000L,2,"}"));
		sList.add(new Statement(serial+17000L,1,"}"));
		sList.add(new Statement(serial+18000L,1,"return max"));
		sList.add(new Statement(serial+19000L,0,"}"));
		
		serial += 20000L;
		for (Method m : this.getMethods()) {
			StatementList msl = m.generateMethodFullStatements();
			msl.setSerial(serial);
			msl.setIndent(1);
			sList.add(msl);
			serial += 1000L;
		}

		return WriteableUtil.merge(sList);
	}
}
